package cs304.p3.library.service;

import java.sql.SQLException;
import java.util.List;

import cs304.p3.library.domain.Book;
import cs304.p3.library.domain.BookCopy;
import cs304.p3.library.domain.BookCopy.BookStatus;
import cs304.p3.library.exceptions.AddBookCopyException;
import cs304.p3.library.exceptions.AddBookException;

public class LibrarianService extends Service {

	public void addBook(String callNumber, String isbn, String title, String mainAuthor,
			List<String> authors, String publisher, int year, List<String> subjects)
			throws AddBookException, AddBookCopyException {
		Book book = new Book(callNumber, isbn, title, mainAuthor, authors, publisher, year,
				subjects);
		addBook(book);
	}

	/**@deprecated use the other addBook() */
	public void addBook(String callNumber, String isbn, String title, String mainAuthor,
			String publisher, int year) throws AddBookException, AddBookCopyException {
		Book book = new Book(callNumber, isbn, title, mainAuthor, publisher, year);
		addBook(book);
	}

	/**
	 * Insert a new book into the Book table.<br>
	 * Also creates the first BookCopy of this book.
	 * 
	 * @param book Book with all fields set.
	 * @throws AddBookException
	 */
	public void addBook(Book book) throws AddBookException, AddBookCopyException {
		try {
			connection.setAutoCommit(false);
			bookDao.insertBook(book);
			// insert all the extra authors into HasAuthor table
			if(book.getAuthors() != null) {
				for(String author: book.getAuthors()) {
					bookDao.insertAuthor(book.getCallNumber(), author);
				}
			}

			// insert all the subjects into HasSubject table
			if(book.getSubjects() != null) {
				for(String subject: book.getSubjects()) {
					bookDao.insertSubject(book.getCallNumber(), subject);
				}
			}

			// First copy is copy 0.
			BookCopy copy = new BookCopy(book.getCallNumber(), 0, BookStatus.IN);
			bookDao.insertBookCopy(copy);
			connection.commit();
			connection.setAutoCommit(true);

		} catch(SQLException e) {
			try {
				String error = "Adding new book failed; rolling back.";
				System.err.println(error);
				connection.rollback();
				throw new AddBookException(book.getCallNumber(), error);
			} catch(SQLException e1) {
				System.err.println(e.getMessage());
				e1.printStackTrace();
				throw new RuntimeException();
			}
		}
	}

	/**
	 * Insert another copy of a book into the BookCopy table.
	 */
	public void addBookCopy(String callNumber) throws AddBookCopyException {
		try {
			// Check that the book exists
			Book b = bookDao.selectBook(callNumber);
			if(b == null) {
				throw new AddBookCopyException("There is no such book to add copies for.",
						callNumber);
			}
			
			BookCopy copy = new BookCopy(callNumber, bookDao.generateCopyNumber(callNumber));
			bookDao.insertBookCopy(copy);
			
		} catch(SQLException e) {
			try {
				System.err.println(e.getMessage());
				String error = "Adding new book copy failed; rolling back.";
				System.err.println(error);
				connection.rollback();
				throw new AddBookCopyException(error, callNumber);
			} catch(SQLException e1) {
				e1.printStackTrace();
				throw new RuntimeException();
			}
		}
	}

	/**
	 * Get a list of books that have been checked out.
	 * 
	 * @param subject Filter by subject, if empty or null this will mean all subjects.
	 * @return
	 */
	public List<BookCopy> getCheckedOut(String subject) {
		try {
			return bookDao.selectCurrentlyBorrowedBooks(subject);
		} catch(SQLException e) {
			try {
				System.err.println(e.getMessage());
				String error = "Selecting borrowed books failed; rolling back.";
				System.err.println(error);
				connection.rollback();
			} catch(SQLException e1) {
				e1.printStackTrace();
				throw new RuntimeException();
			}
		}
		return null;
	}

	/**
	 * Get the top n books for a given year. These are the most commonly checked out books.
	 * 
	 * @param year
	 * @param n
	 * @return
	 */
	public List<Book> getPopularBooks(int year, int n) {
		try {
			return bookDao.selectTopBorrowed(year, n);
		} catch(SQLException e) {
			try {
				System.err.println(e.getMessage());
				System.err.println("Selecting top books failed; rolling back.");
				connection.rollback();
			} catch(SQLException e1) {
				e1.printStackTrace();
				throw new RuntimeException();
			}
		}
		return null;
	}
}
